#ifndef _MY_SERVICE__
#define _MY_SERVICE__
#include"date.hpp"
#include"httplib.h"

extern cloud::DataManager *_date;
namespace cloud
{
    class Service
    {
    private:
        int _server_port;
        std::string _server_ip;
        std::string _download_prefix;
        httplib::Server _server;
    public:
        static void Upload(const httplib::Request &req, httplib::Response &rsp)
        {
            //post /upload 文件数据在正文中（正文并不全是文件数据)
            auto ret=req.has_file("file");
            if(ret ==false)
            {
                rsp.status=400;
                return ;
            }

            const auto &file=req.get_file_value("file");
            //file.filename//文件名称     file.content//文件数据
            std::string back_dir=Config::GetInstance()->GetBackDir();
            std::string realpath=back_dir+FileUtil(file.filename).FileName();
            FileUtil fu(realpath);
            fu.SetContent(file.content);//将数据写入文件中
            BackupInfo info;
            info.NewBackupInfo(realpath);//组织备份的文件中
            _date->Insert(info); //向数据管理模块添加备份的文件信息
            return ;
        }
        static std::string Timetostr(time_t t)
        {
            std::string tmp=std::ctime(&t);
            return tmp;
        }
        static void ListShow(const httplib::Request &req, httplib::Response &rsp)
        {
            //1、获取所有的文件备份信息
            std::vector<BackupInfo> arry;
            _date->GetAll(&arry);
            //2、根据所有的备份信息，组织html文件数据
            std::stringstream ss;
            ss<<"<html><head><title>Download</title></head>";
            ss<<"<body><h1>Download</h1><table>";
            for(auto &a :arry)
            {
                ss<<"<tr>";
                std::string filename=FileUtil(a.real_path).FileName();
                ss<<"<td>< herf='"<<a.url<<"'>"<<filename<<"</a></td>";
                ss<<"td align='right'>"<<Timetostr(a.mtime)<<"</td>";
                ss<<"td align='right'>"<<a.fsize/1024<<"K</td>";
                ss<<"</tr>";
            }
            ss<<"</table></body></html>";
            rsp.body==ss.str();
            rsp.set_header("Content-Type","text/html");
            rsp.status=200;
            return;
        }
        static std::string GetEtag(const BackupInfo &info)
        {
            FileUtil fu(info.real_path);
            std::string etag=fu.FileName();
            etag +='-';
            etag +=std::to_string(info.fsize);
            etag +=std::to_string(info.mtime);
            return etag;
        }
        static void Download(const httplib::Request &req,httplib::Response &rsp)
        {
            //1、获取客户端请求的资源路径 path req.path

            //2、根据资源路径，获取文件的备份信息
            BackupInfo info;
            _date->GetOneByURL(req.path,&info);
            //3、判断文件是否被压缩，如果被压缩，要先解压缩
            if(info.pack_flag==true)
            {
                FileUtil fu(info.real_path);
                fu.UnCompress(info.real_path);//将文件解压到备份目录下
                //  3、1删除压缩包，修改备份信息（已经没有压缩）
                fu.Remove();
                info.pack_flag=false;
                _date->Update(info);
            }
             //4、读取文件数据，放入字段rsq.body中
             FileUtil fu(info.real_path);
            //支持断点续传
            bool rerans=false;
            std::string old_etag;
            if(rsp.has_header("If-Range"))
            {
                old_etag=rsp.get_header_value("If-Range");
                //有If-Range字段且这个字段的值与请求文件的最新etag一致则符合断点续传
                if(old_etag ==GetEtag(info))
                {
                    rerans=true;
                }
            }
            //如果没有If-Range字段则是正常下载，或者如果没有这个字段，但是他的值与当前的etag不一样，则
            //也必须进行重新返回全部数据
            if(rerans ==false)
            {
                fu.GetContent(&rsp.body);
                //5、设置响应头部字段
                rsp.set_header("Accept-Ranges","bytes");
                rsp.set_header("ETag",GetEtag(info));
                rsp.set_header("Content_Type","application/octet-stream");
                rsp.status=200;
            }
            else
            {
                //httplib内部实现了对于区间请求也就是断点续传请求的处理
                //只需要用户将文件所有数据读取到rsp.body中，他内部会自动根据请求区间，从body中取出指定区间数据进行响应
                fu.GetContent(&rsp.body);
                rsp.set_header("Accept-Ranges","bytes");
                rsp.set_header("ETag",GetEtag(info));
                rsp.set_header("Content_Type","application/octet-stream");
                rsp.status=206;
            }
        }
    public:
        Service()
        {
            Config *config=Config::GetInstance();
            _server_port=config->GetServerPort();
            _server_ip=config->GetServerIp();
            _download_prefix=config->GetDownloadPrefix();

        }
        bool RunModule()
        {
            _server.Post("/upload",Upload);
            _server.Get("/listshow",ListShow);
            _server.Get("/",ListShow);
            std::string download_url=_download_prefix+"(.*)";
            _server.Get(download_url,Download);
            _server.listen(_server_ip.c_str(),_server_port);
            return true;
        }
    };
}
#endif